﻿using System;
using System.Collections.Generic;
using JTLeigh.Commerce.Spencer.Core.Common.Entities;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace JTLeigh.Commerce.Spencer.Core.Common.UnitTests.Entities
{

    /// <summary>
    /// Unit tests for the <see cref="CatalogProductReference"/> class.
    /// </summary>
    [TestClass]
    public class CatalogProductReferenceFixture
    {

        #region Methods

        #region Constructors

        /// <summary>
        /// Ensures the constructor stores the catalog identifier and the product identifier 
        /// correctly.
        /// </summary>
        [TestMethod]
        public void TestConstructor()
        {
            CatalogProductReference product;

            product = new CatalogProductReference("TestCatalog", "123");
            Assert.AreEqual("TestCatalog", product.CatalogId);
            Assert.AreEqual("123", product.ProductId);
        }

        #endregion // Constructors

        #region Equals

        /// <summary>
        /// Ensures <see cref="CatalogProductReference.Equals"/> returns <see langword="true"/>
        /// when passed a <see cref="CatalogProductReference"/> object that has the same catalog
        /// identifier and product identifier as the object it's being called on.
        /// </summary>
        [TestMethod]
        public void TestEquals()
        {
            CatalogProductReference product1;
            CatalogProductReference product2;

            product1 = new CatalogProductReference("Catalog", "Product");
            product2 = new CatalogProductReference("Catalog", "Product");
            Assert.IsTrue(product1.Equals(product2));
            Assert.IsTrue(product2.Equals(product1));
        }

        /// <summary>
        /// Ensures <see cref="CatalogProductReference.Equals"/> returns <see langword="true"/>
        /// when passed the object it's being called on.
        /// </summary>
        [TestMethod]
        public void TestEqualsWithSameObject()
        {
            CatalogProductReference product;

            product = new CatalogProductReference("Catalog1", "Product");
            Assert.IsTrue(product.Equals(product));
        }

        /// <summary>
        /// Ensures <see cref="CatalogProductReference.Equals"/> returns <see langword="false"/>
        /// when passed a <see langword="null"/> object.
        /// </summary>
        [TestMethod]
        public void TestEqualsWithNullObject()
        {
            CatalogProductReference product;

            product = new CatalogProductReference("Catalog1", "Product");
            Assert.IsFalse(product.Equals(null));
        }

        /// <summary>
        /// Ensures <see cref="CatalogProductReference.Equals"/> returns <see langword="false"/>
        /// when passed a <see cref="CatalogProductReference"/> object that has a different catalog
        /// identifier than the object it's being called on.
        /// </summary>
        [TestMethod]
        public void TestEqualsWithDifferentCatalogs()
        {
            CatalogProductReference product1;
            CatalogProductReference product2;

            product1 = new CatalogProductReference("Catalog1", "Product");
            product2 = new CatalogProductReference("Catalog2", "Product");
            Assert.IsFalse(product1.Equals(product2));
            Assert.IsFalse(product2.Equals(product1));
        }

        /// <summary>
        /// Ensures <see cref="CatalogProductReference.Equals"/> returns <see langword="false"/>
        /// when passed a <see cref="CatalogProductReference"/> object that has a different product
        /// identifier than the object it's being called on.
        /// </summary>
        [TestMethod]
        public void TestEqualsWithDifferentProducts()
        {
            CatalogProductReference product1;
            CatalogProductReference product2;

            product1 = new CatalogProductReference("Catalog", "Product1");
            product2 = new CatalogProductReference("Catalog", "Product2");
            Assert.IsFalse(product1.Equals(product2));
            Assert.IsFalse(product2.Equals(product1));
        }

        /// <summary>
        /// Ensures <see cref="CatalogProductReference.Equals"/> returns <see langword="false"/>
        /// when passed a non-<see cref="CatalogProductReference"/> object.
        /// </summary>
        [TestMethod]
        public void TestEqualsWithNonProduct()
        {
            CatalogProductReference product;
            DateTime nonProduct;

            product = new CatalogProductReference("Catalog", "Product");
            nonProduct = new DateTime();
            Assert.IsFalse(product.Equals(nonProduct));
            Assert.IsFalse(nonProduct.Equals(product));
        }

        #endregion // Equals

        #region GetHashCode

        /// <summary>
        /// Ensures <see cref="CatalogProductReference.GetHashCode"/> returns identical hash codes
        /// for two <see cref="CatalogProductReference"/> objects with the same catalog identifier
        /// and product identifier.
        /// </summary>
        [TestMethod]
        public void TestGetHashCode()
        {
            CatalogProductReference product1;
            CatalogProductReference product2;

            product1 = new CatalogProductReference("Catalog", "Product");
            product2 = new CatalogProductReference("Catalog", "Product");
            Assert.AreEqual(product1.GetHashCode(), product2.GetHashCode());
        }

        /// <summary>
        /// Ensures <see cref="CatalogProductReference.GetHashCode"/> returns different hash codes
        /// for two <see cref="CatalogProductReference"/> objects with different catalog
        /// identifiers.
        /// </summary>
        [TestMethod]
        public void TestGetHashCodeWithDifferentCatalogs()
        {
            CatalogProductReference product1;
            CatalogProductReference product2;

            product1 = new CatalogProductReference("Catalog1", "Product");
            product2 = new CatalogProductReference("Catalog2", "Product");
            Assert.AreNotEqual(product1.GetHashCode(), product2.GetHashCode());
        }

        /// <summary>
        /// Ensures <see cref="CatalogProductReference.GetHashCode"/> returns different hash codes
        /// for two <see cref="CatalogProductReference"/> objects with different product 
        /// identifiers.
        /// </summary>
        [TestMethod]
        public void TestGetHashCodeWithDifferentProducts()
        {
            CatalogProductReference product1;
            CatalogProductReference product2;

            product1 = new CatalogProductReference("Catalog", "Product1");
            product2 = new CatalogProductReference("Catalog", "Product2");
            Assert.AreNotEqual(product1.GetHashCode(), product2.GetHashCode());
        }

        #endregion // GetHashCode

        #region Other

        /// <summary>
        /// Ensures <see cref="CatalogProductReference"/> can be used as a key in a <see cref="Dictionary{TKey,TValue}"/>.
        /// </summary>
        [TestMethod]
        public void TestUseAsKey()
        {
            Dictionary<CatalogProductReference, string> dictionary;

            dictionary = new Dictionary<CatalogProductReference, string>();
            dictionary[new CatalogProductReference("Catalog", "Product")] = "Value";
            // NOTE: We use two different instances of CatalogProductReference to set and get the 
            // value.
            Assert.AreEqual("Value", dictionary[new CatalogProductReference("Catalog", "Product")]);
        }

        #endregion // Other

        #endregion // Methods

    }

}
